{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Fantasy Hockey on D-Wave\n",
    "\n",
    "In this notebook, we will go through how to perform a Markowitz style portfolio optimization using a D-Wave Quantum Annealer, as opposed to traditional Linear/Quadradic programming solvers. To begin, we first need to define our problem in terms of how it would work as a traditional constrained optimization problem, then how to re-write it as an \"unconstrained\" problem that can be translated as a Binary Quadratic Model (BQM) to be run on D-Wave quantum processors. \n",
    "\n",
    "## The Model\n",
    "\n",
    "If we were taking the classical approach using constrained optimizers, our problem would formally appear as follows:\n",
    "\n",
    "$$\n",
    "\\begin{aligned}\n",
    "\\text{maximize    } \\;\\;& \\mathbf{r x} - \\gamma \\mathbf{x}^T \\mathbf{Qx} \\\\\n",
    "\\text{subject to  } \\;\\;& \\sum_{x_i \\in G} x_i = N_G \\\\\n",
    "& \\sum_{x \\in T} v_i x_i = V \\\\\n",
    "& \\sum_{x_i \\in F} x_i= N_F \\\\\n",
    "& \\sum_{x_i \\in D} x_i = N_D \\\\\n",
    "& \\mathbf{x} \\in \\mathbb{B}.\n",
    "\\end{aligned}\n",
    "$$\n",
    "\n",
    "Where $\\mathbf{r}$ is a returns vector, here defined as the average returns, $\\mathbf{x}$ is a binary vector of players, and $\\mathbf{Q}$ is a covariance matrix of returns. The constraint equations above imply that we _must_ choose some number of players in each position, in this case the indexes $F,D$ and $G$ denote forwards, defence and goalies respectively. We also have a point values constraint represented by $ \\sum_{x \\in T}v_i x_i = V $ where $T$ is the team we have assembled, $v_i$ is the cost of the $i^{th}$ player, and $V$ is the amount of points we can \"spend\" to draft our fantasy team. \n",
    "\n",
    "To make the translation to a problem that we can run on D-Wave, we first rewrite the equation above without matrix notation and write the sums explicitly\n",
    "\n",
    "$$\n",
    "\\begin{aligned}\n",
    "\\text{maximize    } \\;\\;& \\sum_{i=1}^N r_i x_i  - \\gamma \\sum_{i=1}^N \\sum_{j=1}^N q_{ij} x_i x_j \\\\\n",
    "\\text{subject to  } \\;\\;& \\sum_{x_i \\in G} x_i = N_G \\\\\n",
    "& \\sum_{x \\in T} C_i x_i = V \\\\\n",
    "& \\sum_{x_i \\in F} x_i= N_F \\\\\n",
    "& \\sum_{x_i \\in D} x_i = N_D \\\\\n",
    "& \\mathbf{x} \\in \\mathbb{B}\n",
    "\\end{aligned}\n",
    "$$\n",
    "\n",
    "Where $N$ is the number of players. To convert this to a problem we can run on D-Wave, we have to get sneaky. As we cannot specify our constraints in the form we have written here, we have to re-write our above equation in an unconstrained form. Explicitly, we don't want to change our equation, but we do want to make sure that the best solution only appears when the constraints are satisfied. In this case we have two options\n",
    "\n",
    "1. Multiply by 1\n",
    "2. Add zero\n",
    "\n",
    "However, there needs to be something special about these ones and zeros in the sense that they will only be zero when our constraints our satisfied. Explicitly, we will subract the following from our objective function\n",
    "\n",
    "$$ \n",
    " \\lambda_1 \\sum_\\alpha \\left( N_\\alpha - \\sum_i C_{\\alpha, i} x_i \\right)^2 + \\lambda_2\\left(V - \\sum_i v_i x _i \\right) ^2\n",
    "$$\n",
    "\n",
    "where $\\lambda_1$ and $\\lambda_2$ are Lagrange multipliers, $\\alpha$ is a subscript representing $F,G$ and $D$.  The first term above represents our \"position\" constraints (we need to choose so many players in each position). Here the terms $C_{\\alpha, i}$ represents the \"position cost\" of a particular player. That is to say if a player is a defenceman, than the \"costs\" associated with this player are as follows\n",
    "\n",
    "| Constant   | Value for a Defence man  |\n",
    "|------------|--------------------------|\n",
    "| $C_{F,i}$  | 0                        |\n",
    "| $C_{G, i}$ | 0                        |\n",
    "| $C_{D, i}$ | 1                        |\n",
    "\n",
    "Where from the table above, we see that each constant is 1 if a player is the appropriate $\\alpha$ subscript, and 0 otherwise (a defenseman costs nothing from our \"goalie cost pool\"). This allows us to re-write our positional constraints in an \"unconstrained\" manner which will enforce that we select a valid team. The second term in the equation above represents the point value constraint; we must choose players such that the cost of each player we have must all add up to our total budget of $V$.  \n",
    "\n",
    "The two terms above are squared in order to enforce that the minimum of these two terms is strictly zero, and when our constraints are satisfied each of these terms should be zero. \n",
    "\n",
    "Written in full our new optimization problem is\n",
    "\n",
    "$$\n",
    "\\text{maximize} \\; \\;\\sum_{i=1}^N r_i x_i  - \\gamma \\sum_{i=1}^N \\sum_{j=1}^N q_{ij} x_i x_j - \\lambda_1 \\sum_\\alpha \\left( N_\\alpha - \\sum_i C_{\\alpha, i} x_i \\right)^2 - \\lambda_2 \\left(V - \\sum_i v_i x _i \\right) ^2\n",
    "$$\n",
    "\n",
    "Of course, we have to write the above in terms of a Binary Quadratic Model of the form\n",
    "\n",
    "$$ \\sum_i a_i x_i - \\sum_i \\sum_j b_{i,j} x_i x_j $$\n",
    "\n",
    "In order to do this, we have to expand the squared terms in our problem which is done below\n",
    "\n",
    "$$\n",
    "\\begin{aligned}\n",
    "\\sum_\\alpha \\left( N_\\alpha - \\sum_i C_{\\alpha, i} x_i \\right)^2 & = \\sum_\\alpha \\left( N_\\alpha - \\sum_i C_{\\alpha, i} x_i \\right)\\left( N_\\alpha - \\sum_i C_{\\alpha, i} x_i \\right) \\\\\n",
    "& = \\sum_\\alpha \\left(N_\\alpha ^2 + \\sum_i \\sum_j C_{\\alpha, i} C_{\\alpha, j} x_i x_j\\right) - 2 \\sum_\\alpha N_\\alpha \\sum_i C_{\\alpha, i } x_i .\n",
    "\\end{aligned}\n",
    "$$\n",
    "\n",
    "And similarily for the player-value constraint\n",
    "\n",
    "$$\n",
    "\\begin{aligned}\n",
    "\\left(V - \\sum_i v_i x _i \\right) ^2 & = \\left(V - \\sum_i v_i x_i \\right) \\left(V - \\sum_i v_i x _i \\right) \\\\\n",
    "& = V^2 + \\sum_i \\sum_j v_i v_j x_i x_j - 2 V \\sum_i v_i x_i. \n",
    "\\end{aligned}\n",
    "$$\n",
    "\n",
    "\n",
    "Before writing the final expression, we note that the constants $N_\\alpha^2$ and $V^2$ represent a constant offset and won't change the true results of the optimization, we will drop them from the problem. \n",
    "\n",
    "Our final objective function is as follows \n",
    "\n",
    "$$\n",
    "\\begin{aligned} \n",
    "\\text{maximize } & \\; \\sum_i \\left(r_i + 2 \\lambda_1 \\sum_\\alpha N_\\alpha C_{\\alpha,i} + 2 \\lambda_2 V v_i\\right) x_i  \\\\\n",
    "& -\\sum_i \\sum_j \\left( \\gamma q_{ij} + \\lambda_1 \\sum_\\alpha C_{\\alpha, i} C_{\\alpha, j} + \\lambda_2 v_i v_j \\right) x_i x_j \\\\\n",
    "& x \\in \\mathbb{B}.\n",
    "\\end{aligned}\n",
    "$$\n",
    "\n",
    "The file `../scripts/src.py` contains the functions `linearTerms` and `quadraticTerms`, which we will use to calculate the constants for both the linear and quadratic terms respectively. The rest of this notebook demonstrates how to set up the data, and solve the problem using `dimod`, the python package which contains the required functions to complete a problem on a `D-Wave` system.\n",
    "\n",
    "I should note that I wouldn't recommend using this to _actually_ try and win at fantasy sports. An optimization like this would absolutely perform above average in a real set up - but the way I have chosen to set up the data neglects a lot of important covariances between players on opposing teams, and more importantly, some terms which would reward choosing players on the same line would be important. As This is set up for a very simple scoring system of 1 point per goal/assist for players, and 2 points for to each goalie for a win, and an additional point for a shut out. With a system like this, if we chose players on the same lines together when possible we could \"double dip\" in points with assists and perhaps manage up to 3 points per goal. Of course, this should be _partially_ modelled with the covariance terms $q_{ij}$, however, an additional term for strong lines may be necessary. \n",
    "\n",
    "The list of improvements doesn't end there! You could also include terms for how many games may get played etc, as more games = more points, but additional constraints like this have been neglected. \n",
    "\n",
    "## A note on Lagrange Multipliers\n",
    "\n",
    "In the following analysis we will be setting $\\lambda_1 = 1$ and $\\lambda_2 = 0.1$. These values are arbitrary and could be adjusted, however, what they do represent is approximately \"how much we care\" about each constraint. In thise case, we care a lot of we have the right number of players - if we choose an incorrect number of players we will be very bad at fantasy hockey. However, if we choose players such that their points value is _less_ than our budget - that's actually okay - so this is a statement of attempting to punish those violations less severely when it works out well to use \"cheaper\" players. \n",
    "\n",
    "# Data Set Up\n",
    "\n",
    "Here we are not focusing too much on any data wrangling tasks - instead we're focusing on the solutions as described above and using D-Wave solvers to find a solution. Our first step is to import our data and required packages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import sys\n",
    "sys.path.insert(1, '../')\n",
    "import scripts.src as src\n",
    "import dimod"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The data we are importing has been pre-wrangled (mostly). `player_data` contains various statistics of each player, `all_points` is a `csv` organized like \n",
    "\n",
    "```\n",
    "PlayerName1, [list of all points in season scored by player in season]\n",
    "...\n",
    "...\n",
    "```\n",
    "\n",
    "Which allows us to see the variance and statistics of each player. Finally `pvals` is the points value of each player according to the current (as of August 2020) SportsNet Fantasy Playoff draft."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "player_data = pd.read_csv('../data/player_data.csv')\n",
    "del player_data['Unnamed: 0']\n",
    "all_points = pd.read_csv('../data/all_points.csv')\n",
    "del all_points['Unnamed: 0']\n",
    "pvals = pd.read_csv('../data/pvals.csv')\n",
    "pvals = pvals.set_index('name')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here we create our \"position costs\" data set which will allow us to effectively model player constraints as an unconstrained BQM. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>CD</th>\n",
       "      <th>CF</th>\n",
       "      <th>CG</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>name</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Adam Boqvist</th>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Adam Gaudette</th>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Adam Pelech</th>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Adam Werner</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Adin Hill</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Yanni Gourde</th>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Zach Bogosian</th>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Zach Werenski</th>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Zack Smith</th>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Zdeno Chara</th>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>314 rows × 3 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "               CD  CF  CG\n",
       "name                     \n",
       "Adam Boqvist    1   0   0\n",
       "Adam Gaudette   0   1   0\n",
       "Adam Pelech     1   0   0\n",
       "Adam Werner     0   0   1\n",
       "Adin Hill       0   0   1\n",
       "...            ..  ..  ..\n",
       "Yanni Gourde    0   1   0\n",
       "Zach Bogosian   1   0   0\n",
       "Zach Werenski   1   0   0\n",
       "Zack Smith      0   1   0\n",
       "Zdeno Chara     1   0   0\n",
       "\n",
       "[314 rows x 3 columns]"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "players = player_data[['name','position']].drop_duplicates(subset='name')\n",
    "\n",
    "players['costs'] = players.apply(src.costFiller, axis=1)\n",
    "players[['CD','CF','CG']] = pd.DataFrame(players.costs.tolist(), \n",
    "                                          index= players.index)\n",
    "del players['costs']\n",
    "del players['position']\n",
    "players = players.set_index('name')\n",
    "players.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setting Up the BQM\n",
    "\n",
    "The functions below define our BQM. Our linear ($x_i$) terms are created as a dictionary from `src.linearTerms`, and our quadratic ($x_i x_j$) terms are created as a dictonary from `src.quadraticTerms`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "num_each = {'CD':4, 'CF':6, 'CG': 2}\n",
    "# Generating our returns and covariance terms for Markowitz Style Optimizations\n",
    "rets = all_points.mean()#.sample(100)\n",
    "cov  = all_points[list(rets.keys())].cov()\n",
    "    \n",
    "lins = src.linearTerms(rets, players, num_each,pvals)\n",
    "quads = src.quadraticTerms(cov, players, pvals)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As a sanity check (and to make sure we don't have any mistakes before we waste our precious QPU time) we first check with the `SimmulatedAnnealingSampler` locally to see if we can find a solution. If you're testing this, this takes a while with the full set of players chosen (N $\\approx$ 300), and I recommend uncommenting the `#sample(100)` to make things a little faster. It should also be noted that the simulated annealing sampler probably isn't going to converge to an optimal solution in reasonable time. Certainly, you could adjust `num_sweeps` to be larger, but I think you'd have to be pretty patient regardless. That said, if you're looking for an excuse to take a break, I absolutely recommend setting `num_sweeps` to something much higher. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 6min 25s, sys: 820 ms, total: 6min 26s\n",
      "Wall time: 6min 27s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# Appears to scale > N^2, where N is the number of players\n",
    "import dimod \n",
    "bqm = dimod.BQM(lins, \n",
    "                quads,\n",
    "                0,\n",
    "                dimod.BINARY)\n",
    "\n",
    "test = dimod.SimulatedAnnealingSampler().sample(bqm, num_sweeps = 500)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's take a look at our team: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>name</th>\n",
       "      <th>position</th>\n",
       "      <th>PV</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1022</th>\n",
       "      <td>Alex Killorn</td>\n",
       "      <td>L</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1481</th>\n",
       "      <td>Alex Ovechkin</td>\n",
       "      <td>L</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1634</th>\n",
       "      <td>Alex Pietrangelo</td>\n",
       "      <td>D</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3870</th>\n",
       "      <td>Andy Greene</td>\n",
       "      <td>D</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4033</th>\n",
       "      <td>Anthony Cirelli</td>\n",
       "      <td>C</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5442</th>\n",
       "      <td>Bo Horvat</td>\n",
       "      <td>C</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7086</th>\n",
       "      <td>Brian Elliott</td>\n",
       "      <td>G</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7392</th>\n",
       "      <td>Brock Nelson</td>\n",
       "      <td>C</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13411</th>\n",
       "      <td>Dougie Hamilton</td>\n",
       "      <td>D</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17220</th>\n",
       "      <td>Jake Allen</td>\n",
       "      <td>G</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25382</th>\n",
       "      <td>Matthew Tkachuk</td>\n",
       "      <td>L</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37264</th>\n",
       "      <td>Torey Krug</td>\n",
       "      <td>D</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                   name position  PV\n",
       "1022       Alex Killorn        L   2\n",
       "1481      Alex Ovechkin        L   3\n",
       "1634   Alex Pietrangelo        D   2\n",
       "3870        Andy Greene        D   1\n",
       "4033    Anthony Cirelli        C   2\n",
       "5442          Bo Horvat        C   2\n",
       "7086      Brian Elliott        G   3\n",
       "7392       Brock Nelson        C   2\n",
       "13411   Dougie Hamilton        D   2\n",
       "17220        Jake Allen        G   3\n",
       "25382   Matthew Tkachuk        L   3\n",
       "37264        Torey Krug        D   2"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "choices = list(test.first.sample.items())\n",
    "filt = []\n",
    "for name in choices:\n",
    "    if name[1] == 1: \n",
    "        filt.append(name[0])\n",
    "x = player_data[player_data.name.isin(filt)][['name', 'position', 'PV']].drop_duplicates(subset = 'name')\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(12, 27)"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(filt), x.PV.sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Using the QPU\n",
    "Now that things look like they're working, let's check the speed up (and differences in solution) by using the cloud-based QPU solvers from dwave. First I note that you first will have to sign up for a [LEAP](https://www.dwavesys.com/take-leap) account, and set up your API access with instructions at [this link](https://docs.ocean.dwavesys.com/en/latest/overview/sapi.html)\n",
    "\n",
    "## TODO\n",
    "This is all using default parameters in `LeapHybridSampler` -  we may do even better should we tune the parameters a little more carefully."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[StructuredSolver(id='DW_2000Q_6'), UnstructuredSolver(id='hybrid_v1')]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# I don't think this is required but now I'm scared to remove it. \n",
    "from dwave.cloud import Client\n",
    "client = Client.from_config(token='YOUR API KEY HERE') \n",
    "client.get_solvers()     \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 443 ms, sys: 102 ms, total: 545 ms\n",
      "Wall time: 3.03 s\n"
     ]
    }
   ],
   "source": [
    "%%time \n",
    "from dwave.system import LeapHybridSampler\n",
    "bqm = dimod.BQM(lins, \n",
    "                quads,\n",
    "                0,\n",
    "                dimod.BINARY)\n",
    "sampler = LeapHybridSampler()\n",
    "\n",
    "quantum_test = sampler.sample(bqm)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>name</th>\n",
       "      <th>position</th>\n",
       "      <th>PV</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1481</th>\n",
       "      <td>Alex Ovechkin</td>\n",
       "      <td>L</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2183</th>\n",
       "      <td>Alexander Radulov</td>\n",
       "      <td>R</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3407</th>\n",
       "      <td>Andrei Vasilevskiy</td>\n",
       "      <td>G</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7859</th>\n",
       "      <td>Cam Atkinson</td>\n",
       "      <td>R</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11016</th>\n",
       "      <td>Darcy Kuemper</td>\n",
       "      <td>G</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19221</th>\n",
       "      <td>John Carlson</td>\n",
       "      <td>D</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37264</th>\n",
       "      <td>Torey Krug</td>\n",
       "      <td>D</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>38709</th>\n",
       "      <td>Tyler Seguin</td>\n",
       "      <td>C</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>38872</th>\n",
       "      <td>Tyson Barrie</td>\n",
       "      <td>D</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40284</th>\n",
       "      <td>William Karlsson</td>\n",
       "      <td>C</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40437</th>\n",
       "      <td>Yanni Gourde</td>\n",
       "      <td>C</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40598</th>\n",
       "      <td>Zach Werenski</td>\n",
       "      <td>D</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                     name position  PV\n",
       "1481        Alex Ovechkin        L   3\n",
       "2183    Alexander Radulov        R   2\n",
       "3407   Andrei Vasilevskiy        G   4\n",
       "7859         Cam Atkinson        R   2\n",
       "11016       Darcy Kuemper        G   3\n",
       "19221        John Carlson        D   3\n",
       "37264          Torey Krug        D   2\n",
       "38709        Tyler Seguin        C   2\n",
       "38872        Tyson Barrie        D   2\n",
       "40284    William Karlsson        C   2\n",
       "40437        Yanni Gourde        C   1\n",
       "40598       Zach Werenski        D   2"
      ]
     },
     "execution_count": 108,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Q_choices = list(quantum_test.first.sample.items())\n",
    "filt2 = []\n",
    "for name in Q_choices:\n",
    "    if name[1] == 1: \n",
    "        filt2.append(name[0])\n",
    "x2 = player_data[player_data.name.isin(filt2)][['name', 'position', 'PV']].drop_duplicates(subset = 'name')\n",
    "x2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(12, 28)"
      ]
     },
     "execution_count": 109,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(filt2), x2.PV.sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Where we see that the teams are a little different between the two cases. However, what we should note is that the QPU was "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "127.06270627062707"
      ]
     },
     "execution_count": 107,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(6*60 +  25) / 3.03"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Time faster than the other example. It should also be noted that a lot of the time associated with the QPU time is server connection time etc. \n",
    "\n",
    "That said, this may not be a fair comparison as you would likely treat this problem using a more sophisticated classical quadratic programming solver (such as one from [cvxpy](https://www.cvxpy.org/) )."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
